package com.二叉树2;

import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * 删除二叉搜索树中的节点
 * 给定一个二叉搜索树的根节点 root 和一个值 key，删除二叉搜索树中的 key 对应的节点，并保证二叉搜索树的性质不变。返回二叉搜索树（有可能被更新）的根节点的引用。
 *
 * 一般来说，删除节点可分为两个步骤：
 *
 * 首先找到需要删除的节点；
 * 如果找到了，删除它。
 * 说明： 要求算法时间复杂度为 O(h)，h 为树的高度。
 *
 * 示例:
 *
 * root = [5,3,6,2,4,null,7]
 * key = 3
 *
 *     5
 *    / \
 *   3   6
 *  / \   \
 * 2   4   7
 *
 * 给定需要删除的节点值是 3，所以我们首先找到 3 这个节点，然后删除它。
 *
 * 一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。
 *
 *     5
 *    / \
 *   4   6
 *  /     \
 * 2       7
 *
 * 另一个正确答案是 [5,2,6,null,4,null,7]。
 *
 *     5
 *    / \
 *   2   6
 *    \   \
 *     4   7
 *
 * Java
 *
 *
 *
 * 作者：力扣 (LeetCode)
 * 链接：https://leetcode-cn.com/leetbook/read/introduction-to-data-structure-binary-search-tree/xpcnds/
 * 来源：力扣（LeetCode）
 * 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
 */
public class 删除二叉搜索树中的节点 {
    static class Solution {
        /**
         * 1. 如果目标节点没有子节点，我们可以直接移除该目标节点。
         * 2. 如果目标节只有一个子节点，我们可以用其子节点作为替换。
         * 3. 如果目标节点有两个子节点，我们需要用其中序后继节点或者前驱节点来替换，再删除该目标节点。
         *
         * 作者：力扣 (LeetCode)
         * 链接：https://leetcode-cn.com/leetbook/read/introduction-to-data-structure-binary-search-tree/xpyd7r/
         * 来源：力扣（LeetCode）
         * 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
         * @param root
         * @param key
         * @return
         */
        public TreeNode deleteNode(TreeNode root, int key) {
            TreeNode curr = root;
            TreeNode parent = null;
            // 找到要删除的key节点
            while (curr != null && curr.val != key) {
                parent = curr;
                if (key < curr.val) {
                    curr = curr.left;
                } else {
                    curr = curr.right;
                }
            }

            TreeNode keyNode = curr;
            if (keyNode == null) {
                return root;
            }

            // 删除叶子节点
            if (keyNode.left == null && keyNode.right == null) {
                if (parent != null) {
                    // 叶子节点是非根节点
                    if (parent.left == keyNode) {
                        parent.left = null;
                    } else {
                        parent.right = null;
                    }
                } else {
                    // 叶子节点是根节点，就是说整个树只有一个节点
                    return null;
                }
            } else if (keyNode.right == null || keyNode.left == null) {
                // 如果key节点只有左子树或只有右子树， 那么把它的子树的提升到key节点的位置
                TreeNode sub = keyNode.left != null ? keyNode.left : keyNode.right;
                keyNode.val = sub.val;
                keyNode.left = sub.left;
                keyNode.right = sub.right;
                sub.left = null;
                sub.right = null;
            } else {
                // 如果key节点有左右子树，在左子树里找到最大的值，替换到key节点
                TreeNode sub = keyNode.left;
                if (sub.right == null) {
                    keyNode.left = sub.left;
                    keyNode.val = sub.val;
                    sub.left = null;
                } else {
                    parent = sub;
                    while (sub.right != null) {
                        parent = sub;
                        sub = sub.right;
                    }
                    parent.right = sub.left;
                    keyNode.val = sub.val;
                    sub.left = null;
                }
            }
            return root;


        }

        public static void main(String[] args) {
            Solution solution = new Solution();
            TreeNode treeNode = new TreeNode(new Integer[]{2,1,3});

            TreeNode treeNode1 = solution.deleteNode(treeNode, 2);
        }
    }
}
